#include "erpc/erpc.h"
#include "spd_logger.hpp"
#include "simpost_component.hpp"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

class receiver: public simpost::Component
{
public:
    explicit receiver() : Component("receiver", "V1.0.0") {}
    virtual ~receiver() = default;
    bool init(void) override final;
    void exit(void) override final;
private:
    bool socket_init(uint16_t port);
    void report_handler(const google::protobuf::Any &args);
    static void receiver_handler(erpc::erpc_io_t handle, int sockfd, void *args);
private:
    static int m_sockfd;
};

int receiver::m_sockfd = -1;

bool receiver::init(void)
{
    LOG_INFO("receiver init");
    if(false == socket_init(10089))
        return false;
    erpc::erpc_report_subscribe(123, 456, std::bind(&receiver::report_handler, this, std::placeholders::_1));
    return true;
}

void receiver::exit(void)
{
    LOG_INFO("receiver exit");
}

bool receiver::socket_init(uint16_t port)
{
    int reuse = 1;
    struct sockaddr_in addr;
    m_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(m_sockfd < 0)
    {
        LOG_ERROR("create socket error: {}", strerror(errno));
        return false;
    }
    if(setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        LOG_ERROR("setsockopt add reuse error: {}", strerror(errno));
        close(m_sockfd);
        return false;
    }
    if(fcntl(m_sockfd, F_SETFL, fcntl(m_sockfd, F_GETFL) | O_NONBLOCK) < 0)
    {
        LOG_ERROR("fcntl set nonblock error: {}", strerror(errno));
        close(m_sockfd);
        return false;
    }
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htons(INADDR_ANY);
    if(bind(m_sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
    {
        LOG_ERROR("bind socket error: {}", strerror(errno));
        close(m_sockfd);
        return false;
    }
    erpc::erpc_io_register(m_sockfd, receiver_handler, nullptr);
    return true;
}

void receiver::report_handler(const google::protobuf::Any &args)
{
    LOG_INFO("receive a report message");
}

void receiver::receiver_handler(erpc::erpc_io_t handle, int sockfd, void *args)
{
    int result = -1;
    uint8_t buffer[1024];
    struct sockaddr_in addr_in;
    socklen_t addrLen = sizeof(struct sockaddr_in);
    result = recvfrom(m_sockfd, buffer, 1024, 0, (struct sockaddr *)&addr_in, &addrLen);
    if(result < 0)
    {
        LOG_ERROR("recv data error: {}", strerror(errno));
        return ;
    }
    erpc::erpc_dispatch_message(buffer, result);
}

COMPONENT_REGISTER(receiver);
